/******************************************************************************
 * Copyright (C) 2011 ShenZhen ComTop Information Technology Co.,Ltd
 * All Rights Reserved.
 * 本软件为深圳康拓普开发研制。未经本公司正式书面同意，其他任何个人、团体不得使用、
 * 复制、修改或发布本软件.
 *****************************************************************************/

package com.code.common.systeminit;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.servlet.ServletContext;

import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;

import com.code.common.util.StringUtil;

/**
 * 环境工具类
 * 
 * @author 郑重
 * @since 1.0
 * @version 2010-10-15 郑重
 * @version 2013-01-31 陈星凌 集成最小系统的SystemUtils中的方法（获取操作系统名称，判断是否是windows）
 */
public final class EnviromentInfo {
    
    /**
     * 日志
     */
    protected final static Logger LOGGER = LoggerFactory.getLogger("EnviromentInfo");
    
    /**
     * path索引文件
     */
    private final static String RESOURCE = "/SqlMapConfig.xml";
    
    /**
     * web路径
     */
    private final static String WEB = "/web";
    
    /**
     * WEB-INF路径
     */
    private final static String WEB_INF = WEB + "/WEB-INF";
    
    /**
     * 系统配置目录
     */
    private final static String CONFIG_PATH_NAME = "/system-config";
    
    /**
     * 系统配置文件名
     */
    private final static String CONFIG_FILE_NAME = "/ServiceConfig.xml";
    
    /**
     * 全局配置文件名
     */
    private final static String GLOBAL_CONFIG_FILE_NAME = "/config/GlobalConfig.xml";
    
    /** classes目录的路径 */
    private static String classesPath = null;
    
    /** web目录路径 */
    private static String webPath = null;
    
    /** WEB-INF目录的路径 */
    private static String webInfPath = null;
    
    /** lib目录的路径 */
    private static String libPath = null;
    
    /** 服务器操作系统名 */
    private static String osName = null;
    
    /**
     * 系统配置目录
     */
    private static String systemConfigPath = null;
    
    /**
     * 系统环境配置对象
     */
    private static XMLConfiguration configuration;
    
    /**
     * 应用配置对象
     */
    private static XMLConfiguration appConfiguration;
    
    /**
     * 打印列表
     */
    private static List<String> printInfoList = new ArrayList<String>(20);
    
    /**
     * 服务器上下文
     */
    private static ServletContext servletContext;
    
    /**
     * Spring 上下文
     */
    private static WebApplicationContext ctx;
    
    /**
     * 构造函数
     */
    private EnviromentInfo() {
    }
    
    /**
     * 初始化
     */
    public static void init() {
        addPrintList("[信息]初始化EnviromentInfo开始");
        initEnviromentConfig();
        initEnviromentPath();
        initApplicationConfig();
        initLog();
        addPrintList("[信息]初始化EnviromentInfo结束");
        printList();
        initOsName();
    }
    
    /**
     * 初始化操作系统名
     */
    private static void initOsName() {
    	osName = System.getProperty("os.name")
		.toLowerCase(Locale.getDefault());
    }
    
    /**
     * 初始化环境配置
     */
    private static void initEnviromentConfig() {
        
        // 2012-02-22 李志勇修改获取域路径的方式。之前的方式
        // Servlet.class.getClassLoader().getResource(StringUtils.EMPTY).getPath()
        // 在weblogic11下取值有问题。System.getProperty("user.dir")这种方式只适应于weblogic.
        // 不过此类的目的是取到weblogic域路径，满足需求。
        String strDomainPath = System.getProperty("user.dir");
        // Servlet.class.getClassLoader().getResource(StringUtils.EMPTY).getPath();
        systemConfigPath = trimPath(strDomainPath);
        // / 打印路径
        addPrintList("[信息]systemConfigPath=" + systemConfigPath);
        String strConfigPath = CONFIG_PATH_NAME + CONFIG_FILE_NAME;
        File objConfigPath = new File(systemConfigPath + strConfigPath);
        try {
            if (!objConfigPath.exists()) {
                // 优先加载域目录下的配置文件,当域目录下不存在时加载classpath下的配置文件
                objConfigPath = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + strConfigPath);
                addPrintList("[警告]域服务配置文件" + systemConfigPath + strConfigPath + "不存在" + ",加载classpach下的"
                    + objConfigPath.getPath());
            }
            if (objConfigPath.exists()) {
	            configuration = new XMLConfiguration(objConfigPath);
	            configuration.setEncoding("UTF-8");
	            configuration.setReloadingStrategy(new FileChangedReloadingStrategy());
	            addPrintList("[信息]ServiceConfig.xml=" + trimPath(objConfigPath.getPath()));
            }
        } catch (Throwable e) {
            System.err.println("[错误]ServiceConfig.xml=" + trimPath(objConfigPath.getPath()) + ":" + e);
        }
    }
    
    /**
     * 设置环境路径
     */
    private static void initEnviromentPath() {
        String strClassesPath = null;
        try {
            URL objResURL = EnviromentInfo.class.getResource(RESOURCE);
            String strResPath = objResURL.getFile();
            strClassesPath = substringBefore(strResPath, RESOURCE);
            // / classes 路径
            classesPath = trimPath(strClassesPath);
            // / web 路径
            webPath = getRootPath(strClassesPath) + WEB;
            // / WEB-INF 路径
            webInfPath = getRootPath(strClassesPath) + WEB_INF;
        } catch (Throwable ex) {
            addPrintList("[错误]定位classes目录失败,请将保证在classes下存在资源文件:" + RESOURCE);
        }
        // lib(APP-INF/lib or WEB-INF/lib)
        int iIndex = strClassesPath.lastIndexOf('/', strClassesPath.length() - 2);
        libPath = StringUtil.substring(strClassesPath, 0, iIndex) + "/lib";
        // / 打印路径
        addPrintList("[信息]web_path=" + webPath);
        addPrintList("[信息]web_inf_path=" + webInfPath);
        addPrintList("[信息]classes_path=" + classesPath);
        addPrintList("[信息]lib_path=" + libPath);
    }
    
    /**
     * 初始化应用配置
     */
    private static void initApplicationConfig() {
        try {
            File objConfigPath = new File(webInfPath + GLOBAL_CONFIG_FILE_NAME);
            appConfiguration = new XMLConfiguration(objConfigPath);
            appConfiguration.setEncoding("UTF-8");
            appConfiguration.setReloadingStrategy(new FileChangedReloadingStrategy());
            addPrintList("[信息]appConfigPath=" + webInfPath + GLOBAL_CONFIG_FILE_NAME);
        } catch (Throwable e) {
            addPrintList("[错误]appConfigPath=" + webInfPath + GLOBAL_CONFIG_FILE_NAME + e);
        }
    }
    
    /**
     * 设置logback
     */
    private static void initLog() {
        String strServerConfig = getServerConfig(ServerConstant.LOG_CONFIGURATION);
        Assert.notNull(strServerConfig, "配置项" + ServerConstant.LOG_CONFIGURATION + "不存在");
        try {
            File objIstream = new File(strServerConfig);
            ILoggerFactory objLoggerFactory = LoggerFactory.getILoggerFactory();
            LoggerContext objLoggerContext = (LoggerContext) objLoggerFactory;
            objLoggerContext.setMaxCallerDataDepth(100);
            objLoggerContext.reset();
            JoranConfigurator objConfigurator = new JoranConfigurator();
            objConfigurator.setContext(objLoggerContext);
            objConfigurator.doConfigure(objIstream);
            SLF4JBridgeHandler.install();
            // / 设置日志输出文件路径
            addPrintList("[信息]日志配置信息=" + trimPath(objIstream.getPath()) + " 加载成功");
        } catch (Throwable e) {
            addPrintList("[错误]日志配置信息=" + strServerConfig + " 加载失败" + e);
        }
    }
    
    /**
     * 取得根路径
     * 
     * @param path 路径
     * @return String
     */
    private static String getRootPath(String path) {
        StringBuffer sbResult = new StringBuffer(256);
        String[] strPaths = path.split("/");
        for (int i = 0; i < strPaths.length - 2; i++) {
            sbResult.append(strPaths[i]).append("/");
        }
        return sbResult.toString().replaceAll("/$", "");
    }
    
    /**
     * 取前缀
     * 
     * @param str 字符串
     * @param separator 分隔符
     * @return String
     */
    private static String substringBefore(String str, String separator) {
        if (str == null || separator == null || str.length() == 0) {
            return str;
        }
        if (separator.length() == 0) {
            return StringUtil.EMPTY;
        }
        int iPos = str.indexOf(separator);
        if (iPos == -1) {
            return str;
        }
        return str.substring(0, iPos);
    }
    
    /**
     * 去掉最后的'/'
     * 
     * @param str 字符串
     * @param separator 分隔符
     * @return String
     */
    private static String chomp(String str, String separator) {
        if (str == null || str.length() == 0 || separator == null) {
            return str;
        }
        if (str.endsWith(separator)) {
            return str.substring(0, str.length() - separator.length());
        }
        return str;
    }
    
    /**
     * 修正路径. 将'\'替换成'/'
     * 
     * @param strPath 路径
     * @return 返回Java默认格式的路径
     */
    private static String trimPath(String strPath) {
        String strNewPath = StringUtil.replace(strPath, "\\", "/");
        // / 去掉最后的'/'
        strNewPath = chomp(strNewPath, "/");
        return strNewPath;
    }
    
    /**
     * 加入打印列表
     * 
     * @param info 打印信息
     */
    private static void addPrintList(String info) {
        printInfoList.add(info);
    }
    
    /**
     * 加入打印列表
     */
    private static void printList() {
        for (String strInfo : printInfoList) {
            LOGGER.error(strInfo);
        }
    }
    
    /**
     * @return classesPath
     */
    public static String getClassesPath() {
        return classesPath;
    }
    
    /**
     * @return libPath
     */
    public static String getLibPath() {
        return libPath;
    }
    
    /**
     * @return webInfPath
     */
    public static String getWebInfPath() {
        return webInfPath;
    }
    
    /**
     * @return webPath
     */
    public static String getWebPath() {
        return webPath;
    }
    
    /**
     * @return 获取 systemConfigPathString属性值
     */
    public static String getSystemConfigPath() {
        return systemConfigPath;
    }
    
    /**
     * @return 获取 servletContext属性值
     */
    public static ServletContext getServletContext() {
        return servletContext;
    }
    
    /**
     * @param servletContext 设置 servletContext 属性值为参数值 servletContext
     */
    public static void setServletContext(ServletContext servletContext) {
        EnviromentInfo.servletContext = servletContext;
    }
    
    /**
     * 返回Spring容器
     * 
     * @return Spring容器
     */
    public static WebApplicationContext getWebApplicationContext() {
        if (ctx == null) {
            ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
        }
        return ctx;
    }
    
    /**
     * 获取服务配置项
     * 
     * @param key 配置键名
     * @return 配置值
     */
    public static String getServerConfig(String key) {
        return configuration.getString(key);
    }
    
    /**
     * 全局配置项
     * 
     * @param key 配置键名
     * @return 配置值
     */
    public static String getGlobalConfig(String key) {
        return appConfiguration.getString(key);
    }
    
    /**
     * 获取配置文件GlobalConfig.xml的最后更新时间
     * 
     * @return GlobalConfig.xml文件的最后更新时间
     */
    public static long getPublishDate() {
        return appConfiguration.getFile().lastModified();
    }
    
	/**
	 * 获取服务器操作系统类型
	 * @return 服务器操作系统名
	 */
	public final static String getOsName(){
		return osName;
	}

	/**
	 * 服务器是否windows
	 * 
	 * @return 服务器是否是windows系统
	 */
	public static boolean isWindows() {
		return osName.contains("windows");
	}
	
}